﻿namespace LightCAD.Core.Elements.Basic
{
    public class LcTable : LcElement
    {
        // 列数
        public int ColumnCount;
        // 行数
        public int RowCount;
        // 列宽
        public double ColumnWidth;
        // 行高
        public double RowHeight;
        // 单元格样式
        public string[] CellTypes;
        // 开始坐标
        public Vector2 FirstPoint;
        // 结束坐标
        public Vector2 EndPoint;

        public List<LcTableCell> Cells;

        public Box2 Box2D;

        public LcTable()
        {
            this.Type = BuiltinElementType.Table;
        }

        public override LcElement Clone()
        {
            var clone = new LcTable();
            clone.Copy(this);
            return clone;
        }

        public void Set(Vector2 start = null, Vector2 end = null, int? columnCount = null, int? rowCount = null,
            double? columnWidth = null, double? rowHeight = null, bool fireChangedEvent = true)
        {
            if (!fireChangedEvent)
            {
                if (start != null) this.FirstPoint = start;
                if (end != null) this.EndPoint = end;
            }
            else
            {
                bool chg_start = (start != null && start != this.FirstPoint);
                if (chg_start)
                {
                    OnPropertyChangedBefore(nameof(start), this.FirstPoint, start);
                    var oldValue = this.FirstPoint;
                    this.FirstPoint = start;
                    OnPropertyChangedAfter(nameof(start), oldValue, this.FirstPoint);
                }

                bool chg_end = (end != null && end != this.EndPoint);
                if (chg_end)
                {
                    OnPropertyChangedBefore(nameof(end), this.EndPoint, end);
                    var oldValue = this.EndPoint;
                    this.EndPoint = end;
                    OnPropertyChangedAfter(nameof(end), oldValue, this.EndPoint);
                }
                this.Box2D = new Box2().SetFromPoints(this.FirstPoint, this.EndPoint);

                bool chg = (columnCount != null && columnCount != this.ColumnCount);
                if (chg)
                {
                    OnPropertyChangedBefore(nameof(columnCount), this.ColumnCount, columnCount);
                    var oldValue = this.ColumnCount;
                    this.ColumnCount = columnCount.Value;
                    OnPropertyChangedAfter(nameof(columnCount), oldValue, this.ColumnCount);
                }

                chg = (rowCount != null && rowCount != this.RowCount);
                if (chg)
                {
                    OnPropertyChangedBefore(nameof(rowCount), this.RowCount, rowCount);
                    var oldValue = this.RowCount;
                    this.RowCount = rowCount.Value;
                    OnPropertyChangedAfter(nameof(rowCount), oldValue, this.RowCount);
                }

                chg = (columnWidth != null && columnWidth != this.ColumnWidth);
                if (chg)
                {
                    OnPropertyChangedBefore(nameof(columnWidth), this.ColumnWidth, columnWidth);
                    var oldValue = this.ColumnWidth;
                    this.ColumnWidth = columnWidth.Value;
                    OnPropertyChangedAfter(nameof(columnWidth), oldValue, this.ColumnWidth);
                }

                chg = (rowHeight != null && rowHeight != this.RowHeight);
                if (chg)
                {
                    OnPropertyChangedBefore(nameof(rowHeight), this.RowHeight, rowHeight);
                    var oldValue = this.RowHeight;
                    this.RowHeight = rowHeight.Value;
                    OnPropertyChangedAfter(nameof(rowHeight), oldValue, this.RowHeight);
                }

                foreach (var item in this.Cells)
                {
                    item.Set(tableStart: this.FirstPoint, columnWidth: this.ColumnWidth, rowHeight: this.RowHeight);
                }
            }
        }

        public override void Translate(double dx, double dy)
        {
            var ts = new Vector2(this.FirstPoint.X + dx, this.FirstPoint.Y + dy);
            var te = new Vector2(this.EndPoint.X + dx, this.EndPoint.Y + dy);
            Set(ts, te);
            ResetBoundingBox();
        }

        public override Box2 GetBoundingBox()
        {
            return new Box2().SetFromPoints(this.FirstPoint, this.EndPoint);
        }
        public override Box2 GetBoundingBox(Matrix3 matrix)
        {
            return new Box2().SetFromPoints(matrix.MultiplyPoint(this.FirstPoint), matrix.MultiplyPoint(this.EndPoint));
        }

        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                //如果元素盒子，与多边形盒子不相交，那就可能不相交
                return false;
            }
            return GeoUtils.IsPolygonIntersectLine(testPoly.Points, this.FirstPoint, this.EndPoint)
                || GeoUtils.IsPolygonContainsLine(testPoly.Points, this.FirstPoint, this.EndPoint);
        }

        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                return false;
            }
            return GeoUtils.IsPolygonContainsLine(testPoly.Points, this.FirstPoint, this.EndPoint);
        }
    }
}
